package leetcode_jz_offer;

/**
 * @author 美女
 * @date 2022/08/15 13:34
 **/
public class Num33_二叉搜索树的后序遍历序列 {
    //后序遍历：左右根
    public boolean verifyPostorder(int[] postorder) {
        return recur(postorder,0,postorder.length-1);
    }
    /**
     * 递推工作：
     * 划分左右子树：
     * 遍历后序遍历的[i,j] 区间元素，寻找第一个大于根节点的节点，索引记为m
     * 此时，可划分出左子树区间[i,m−1]、右子树区间[m,j−1]、根节点索引j
     * 判断是否为二叉搜索树：
     * 左子树区间[i,m−1]内的所有节点都应<postorder[j]。而划分左右子树步骤已经保证左子树区间的正确性，因此只需要判断右子树区间即可。
     * 右子树区间[m,j−1]内的所有节点都应>postorder[j] 。实现方式为遍历，当遇到postorder[j]≤postorder[j] 的节点则跳出；则可通过p=j判断是否为二叉搜索树。
     */

    private boolean recur(int[] postorder,int i,int j){
        if(i>=j){
            return true;
        }
        int p=i;
        while(postorder[p]<postorder[j]){
            p++;
        }
        int m=p;//m索引对应的是第一个大于根节点的数
        //上面的遍历也保证了左子树区间节点值all小于根节点
        //继续遍历保证右子树区间都是大于根节点值的
        while(postorder[p]>postorder[j]){
            p++;
        }
        //将整个数组遍历完p若是加到了最后一个数，即p==j时，就能确定是个二叉搜索树
        //p==j:判断根节点位置对应；recur(postorder,i,m-1):判断左子树是否二叉搜索树；recur(postorder,m,j-1):判断右子树是否二叉搜索树
        return p==j&&recur(postorder,i,m-1)&&recur(postorder,m,j-1);
    }
}
